package com.code.generate.controller;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.fastjson.JSONObject;
import com.code.generate.controller.history.BaseController;
import com.code.generate.model.*;
import com.code.generate.util.FreemarkerUtil;
import com.code.generate.util.GCM_DB_util;
import com.code.generate.util.GsonUtil;
import com.code.generate.util.JsonRecordUtil;
import com.code.generate.vo.ColumnConfig;
import com.code.generate.vo.ColumnInfo;
import com.code.generate.vo.ResultData;
import com.code.generate.vo.TableInfo;
import com.google.common.io.Files;
import com.google.common.reflect.TypeToken;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.DbPro;
import com.jfinal.plugin.activerecord.Record;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;


@Slf4j
@RestController
@RequestMapping("/template")
public class TemplateController extends BaseController {

    static String filePath;

    public String getFilePath(){
        if(StrUtil.isBlank(filePath) || !FileUtil.exist(filePath)){
            File tempFile = Files.createTempDir();//创建临时文件夹
            filePath = tempFile.getAbsolutePath();
        }
        return filePath;
    }

    @RequestMapping(value = "/list", method = {RequestMethod.POST,RequestMethod.GET})
    public ResultData list(@RequestParam(value = "projectId")String projectId,
                           @RequestParam(value = "tableName",required = false)String tableName) throws Exception {
        List<Template> dataList = Template.dao.find("select * from template where project_id = ?", projectId);

        if (dataList != null && dataList.size() > 0) {


            for (int i = 0; i < dataList.size(); i++) {
                // 获得已经关联的 configId
                List<Integer> configIdList = new ArrayList<Integer>();
                List<ConfigRecord> configRecordList = ConfigRecord.dao.find(
                        "select * from config_record where template_id= ? and project_id=?",
                        dataList.get(i).getTemplateId(), projectId);
                if (configRecordList != null && configRecordList.size() > 0) {
                    for (int j = 0; j < configRecordList.size(); j++) {
                        configIdList.add(configRecordList.get(j).getConfigId());
                    }
                }
                dataList.get(i).put("configIdList", configIdList);
                dataList.get(i).put("columnsList", new ArrayList<Map<String, Object>>());
                if (StrKit.notBlank(tableName)) {
                    Project project = Project.dao.findById(projectId);
                    JdbcConfig jdbcConfig = JdbcConfig.dao.findById(project.getJdbcConfigId());
                    DbPro dbPro = GCM_DB_util.getDb(project);
                    // 列信息
                    List<Record> listBaseCoumnInfo = dbPro.find(
                            "SELECT * FROM information_schema. COLUMNS WHERE table_schema = ? and TABLE_NAME=?",
                            jdbcConfig.getDbName(), tableName);
                    List<Map<String, Object>> columnsList = new ArrayList<Map<String, Object>>();
                    if (listBaseCoumnInfo != null && listBaseCoumnInfo.size() > 0) {
                        Map<String, Object> columnMap = null;
                        List<Config> configListTemp = Config.dao.find(
                                "select * from config where config_id in(select config_id from config_record where template_id= ? and project_id=?)",
                                dataList.get(i).getTemplateId(), projectId);

                        for (int j = 0; j < configListTemp.size(); j++) {
                            List<ConfigKeyVal> configKeyValList = ConfigKeyVal.dao.find(
                                    "select * from configKeyVal where config_id =?",
                                    configListTemp.get(j).getConfigId());
                            configListTemp.get(j).put("configKeyValList", configKeyValList);
                            configListTemp.get(j).put("checkValList", new ArrayList<Object>());
                            configListTemp.get(j).put("checkVal", "");
                        }

                        for (int k = 0; k < listBaseCoumnInfo.size(); k++) {
                            columnMap = new HashMap<String, Object>();
                            ColumnInfo columnInfo = new ColumnInfo(listBaseCoumnInfo.get(k).getColumns());
                            columnMap.put("columnInfo", columnInfo);
                            columnMap.put("configList", configListTemp);
                            columnsList.add(columnMap);
                        }
                    }
                    dataList.get(i).put("columnsList", columnsList);
                }
                // dataList.get(i).put("configRecordList", configRecordList);

            }
        }
        dataList = JsonRecordUtil.convertList(dataList);
        return ResultData.buildSuccess(dataList);
    }
    @RequestMapping(value = "/del", method = {RequestMethod.POST,RequestMethod.GET})
    public ResultData get(@RequestParam("templateId")String templateId) {
        Template template = Template.dao.findById(templateId);
        if (template == null) {
            return ResultData.buildFailure("查无数据，删除失败");
        }
        Db.delete("delete from config_record where project_id=? and template_id=?", template.getProjectId(),
                template.getTemplateId());
        template.delete();
        return ResultData.buildSuccess();
    }

    @RequestMapping("/download")
    public void downImg(@RequestParam(value = "fileName")String fileName,@RequestParam(value = "tableName",required = false)String tableName,  HttpServletResponse response){
        if (fileName != null) {
            FileInputStream is = null;
            BufferedInputStream bs = null;
            OutputStream os = null;
            try {
                File file = new File(getFilePath().concat(File.separator).concat(fileName));
                if (file.exists()) {
                    //设置Headers
                    response.setHeader("Content-Type","application/octet-stream");
                    //设置下载的文件的名称-该方式已解决中文乱码问题
                    String downloadFileName = fileName;
                    if(StringUtils.isNotBlank(tableName)){
                        downloadFileName = tableName.concat(".zip");
                    }
                    response.setHeader("Content-Disposition","attachment;filename=" +  new String( downloadFileName.getBytes("gb2312"), "ISO8859-1" ));
                    is = new FileInputStream(file);
                    bs =new BufferedInputStream(is);
                    os = response.getOutputStream();
                    byte[] buffer = new byte[1024];
                    int len = 0;
                    while((len = bs.read(buffer)) != -1){
                        os.write(buffer,0,len);
                    }
                }else{
//                    String error = Base64Util.encode();
                    response.sendError(404,"亲～ 下载的文件资源不存在");
                }
            }catch(IOException ex){
                ex.printStackTrace();
            }finally {
                try{
                    if(is != null){
                        is.close();
                    }
                    if( bs != null ){
                        bs.close();
                    }
                    if( os != null){
                        os.flush();
                        os.close();
                    }
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }


    @RequestMapping(value = "/saveUpdate", method = {RequestMethod.POST,RequestMethod.GET})
    public ResultData saveUpdate(@RequestParam(value = "project_id",required = true)Integer project_id,
                                 @RequestParam(value = "template_id",required = false)Integer template_id,
                                 @RequestParam(value = "name",required = false)String name,
                                 @RequestParam(value = "path",required = false)String path,
                                 @RequestParam(value = "content",required = false)String content,
                                 @RequestParam(value = "configIdList",required = false)String configIdList) {
        Template template = new Template();
        template.setName(name);
        template.setProjectId(project_id);
        template.setPath(path);
        template.setContent(content);

        if (template_id != null) {
            template.setTemplateId(template_id);
        }
        if (template_id == null) {
            template.save();
            if (name == null) {
                template.setName("模板-" + template.getTemplateId() + "");
            }
        }
        template.update();
        // 删除
        Db.delete("delete from config_record where  project_id=? and template_id=? ", template.getProjectId(),
                template.getTemplateId());
        if (StrKit.notBlank(configIdList)) {
            String[] configIds = configIdList.split(",");
            if (configIds.length > 0) {
                Set<String> setData = new HashSet<String>(Arrays.asList(configIds));
                for (String data : setData) {
                    ConfigRecord configRecord = new ConfigRecord();
                    configRecord.setProjectId(template.getProjectId());
                    configRecord.setConfigId(Integer.valueOf(data));
                    configRecord.setTemplateId(template.getTemplateId());
                    configRecord.save();
                }
            }
        }

        return ResultData.buildSuccess();
    }

    @RequestMapping(value = "/generateCode", method = {RequestMethod.POST,RequestMethod.GET})
    public ResultData generateCode(@RequestBody List<Map<String,String>> list) throws Exception {
        log.info("generateCode list:{}",list);
        String uuid = IdUtil.simpleUUID();
        String tableName = null;
        String generateFilePath = getFilePath().concat(File.separator).concat(uuid).concat(File.separator);
        FileUtil.mkdir(generateFilePath);
        log.info("generateFilePath : {}",generateFilePath);
        for (int i = 0; i < list.size(); i++) {

            Map<String,String> map = list.get(i);
            log.info("generateCode map:{}",map);
            Template template = Template.dao.findById(map.get("templateId"));
            // 数据
            TableInfo tableInfo = generateBean(map);
            String fileName = FreemarkerUtil.createStr(template.getPath(), tableInfo);
            String generateFilePathTemp = generateFilePath.concat(fileName);
            log.info("generateFilePath:{} fileName: {}  generateFilePathTemp:{}",generateFilePath,fileName,generateFilePathTemp);
            FreemarkerUtil.createFile(template.getContent(), tableInfo, generateFilePathTemp);
            log.info("generateCode end i:{}",i);
            if(StrKit.isBlank(tableName)){
                tableName = map.get("tableName");
            }
        }

        ZipUtil.zip(generateFilePath);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("fileName",uuid.concat(".zip"));
        jsonObject.put("tableName",tableName);
        return ResultData.buildSuccess(jsonObject);
    }
    @RequestMapping(value = "/generateCodeJson", method = {RequestMethod.POST,RequestMethod.GET})
    public ResultData generateCodeJson(@RequestBody Map<String,String> map) throws Exception {
        // 数据
        TableInfo tableInfo = generateBean(map);
        return ResultData.buildSuccess(GsonUtil.toJson(tableInfo));
    }
    private TableInfo generateBean(Map<String,String> map) throws Exception {

        String projectId = map.get("projectId");

        Project project = Project.dao.findById(projectId);

        String tableName = map.get("tableName");

        JdbcConfig jdbcConfig = JdbcConfig.dao.findById(project.getJdbcConfigId());
        DbPro dbPro = GCM_DB_util.getDb(project);

        TableInfo tableInfo = new TableInfo();

        // 表信息
        Record baseTableInfo = dbPro.findFirst(
                "SELECT * FROM INFORMATION_SCHEMA.tables WHERE TABLE_SCHEMA = ? and table_name = ?  ORDER BY table_name asc",
                jdbcConfig.getDbName(), tableName);

        tableInfo.setBaseTableInfoMap(baseTableInfo.getColumns());

        // 列信息
        List<Record> listBaseCoumnInfo = dbPro.find(
                "SELECT * FROM information_schema. COLUMNS WHERE table_schema = ? and TABLE_NAME=?",
                jdbcConfig.getDbName(), tableName);

        List<ColumnInfo> listColumnInfo = new ArrayList<ColumnInfo>();
        if (listBaseCoumnInfo != null && listBaseCoumnInfo.size() > 0) {
            for (int i = 0; i < listBaseCoumnInfo.size(); i++) {
                ColumnInfo columnInfo = new ColumnInfo(listBaseCoumnInfo.get(i).getColumns());
                // 设置一些配置的属性
                setColumnInfoConfig(map,columnInfo);

                listColumnInfo.add(columnInfo);
            }
        }
        tableInfo.setListColumnInfo(listColumnInfo);
        log.error("tableInfo:" + GsonUtil.toJson(tableInfo));
        return tableInfo;
    }

    // 设置 字段 config配置
    @SuppressWarnings("unchecked")
    public void setColumnInfoConfig(Map<String,String> map,ColumnInfo columnInfo) {
        String columnsListStr = map.get("columnsListStr");

        if (StrKit.notBlank(columnsListStr)) {
            List<Map<String, Object>> columnsList = GsonUtil.fromJson(columnsListStr,
                    new TypeToken<List<Map<String, Object>>>() {
                    }.getType());
            if (columnsList != null) {
                for (int i = 0; i < columnsList.size(); i++) {
                    Map<String, Object> columnsMap = columnsList.get(i);
                    ColumnInfo columnInfoTmp = GsonUtil.fromJson(GsonUtil.toJson(columnsMap.get("columnInfo")),
                            ColumnInfo.class);
                    if (columnInfo != null
                            && columnInfo.getColumnName().equalsIgnoreCase(columnInfoTmp.getColumnName())) {
                        List<Map<String, Object>> configList = (List<Map<String, Object>>) columnsMap.get("configList");
                        columnInfo.setColumnConfig(new ColumnConfig(configList));
                    }
                }
            }
        }
    }
}